﻿using System;
using System.Drawing;
using System.Text.RegularExpressions;
using Kaleida.ServiceMonitor.Model.ColourSpecifications;
using NUnit.Framework;

namespace Kaleida.UnitTests.Model.ColourSpecifications
{
	[TestFixture]
	public class RangeStateColourSpecificationTests
	{
		[Test]
		public void TestDescription()
		{
			Assert.AreEqual("5 to 9 failures: Red", RangeStateColourSpecification.WithBounds(Color.Red, FailureCountMetric.Instance, 5, 9).Description);
            Assert.AreEqual("1 failure: Blue", RangeStateColourSpecification.WithBounds(Color.Blue, FailureCountMetric.Instance, 1, 1).Description);

            Assert.AreEqual("1 or fewer failures: Red", RangeStateColourSpecification.WithUpperBound(Color.Red, FailureCountMetric.Instance, 1).Description);
            Assert.AreEqual("100 or fewer failures: Red", RangeStateColourSpecification.WithUpperBound(Color.Red, FailureCountMetric.Instance, 100).Description);
            Assert.AreEqual("1 or fewer failures: Blue", RangeStateColourSpecification.WithUpperBound(Color.Blue, FailureCountMetric.Instance, 1).Description);
            Assert.AreEqual("3 or fewer failures: Yellow", RangeStateColourSpecification.WithUpperBound(Color.Yellow, FailureCountMetric.Instance, 3).Description);

            Assert.AreEqual("100 or more failures: Red", RangeStateColourSpecification.WithLowerBound(Color.Red, FailureCountMetric.Instance, 100).Description);
            Assert.AreEqual("1 or more failures: Blue", RangeStateColourSpecification.WithLowerBound(Color.Blue, FailureCountMetric.Instance, 1).Description);
            Assert.AreEqual("3 or more failures: Yellow", RangeStateColourSpecification.WithLowerBound(Color.Yellow, FailureCountMetric.Instance, 3).Description);
		}

		[Test]
		public void TestCanParseCanonicalFormat()
		{
			Assert.AreEqual("2 to 9 failures: Yellow", RangeStateColourSpecification.Parse("2-9 failures Yellow").Description);
			Assert.AreEqual("1 failure: Yellow", RangeStateColourSpecification.Parse("1 failure Yellow").Description);
		}

		[Test]
		public void TestParseSupportsDifferentFormatsForSubjectMetric()
		{
			Assert.AreEqual("2 to 9 failures: Yellow", RangeStateColourSpecification.Parse("2-9 failures Yellow").Description, "Failure-count is assumed if subject is omitted");
			Assert.AreEqual("2 to 3 failures: Red", RangeStateColourSpecification.Parse("2-3 failure Red").Description, "Singular-plural agreement is not necessary");
			Assert.AreEqual("1 failure: Red", RangeStateColourSpecification.Parse("1 failure Red").Description, "Singular-plural agreement is allowed");
		}

        [Test]
        public void TestParseSuccessRateMetric()
        {
            Assert.AreEqual("0 to 0.8 success-rate: Yellow", RangeStateColourSpecification.Parse("0%-80% success-rate Yellow").Description);
        }

		[Test]
		public void TestParseSupportsDifferentColourFormats()
		{
			Assert.AreEqual("2 to 9 failures: Yellow", RangeStateColourSpecification.Parse("2-9 failures Yellow").Description, "Canonical format");
			Assert.AreEqual("2 to 9 failures: Blue", RangeStateColourSpecification.Parse("2-9 failures BlUe").Description, "Colour name is case-independant");
			Assert.AreEqual("2 to 9 failures: Yellow", RangeStateColourSpecification.Parse("2-9 failures   Yellow  ").Description, "Leading and trailing spaces are permitted");
		}

		[Test]
		public void TestCanParseBoundedRange()
		{
			Assert.AreEqual("2 to 9 failures: Yellow", RangeStateColourSpecification.Parse("2-9 failures Yellow").Description, "Canonical format");
			Assert.AreEqual("80 to 100 failures: Red", RangeStateColourSpecification.Parse("80-100 failure Red").Description, "Two and three digit numbers are supported");
			Assert.AreEqual("2 to 5 failures: Blue", RangeStateColourSpecification.Parse("2->5 failures Blue").Description, "range may be specified using an arrow");
			Assert.AreEqual("2 to 5 failures: Blue", RangeStateColourSpecification.Parse("2-5 failures blue").Description, "Colour name is case-independant");
		}


        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "minimum cannot be more than maximum. minimum=9, maximum=2")]
		public void TestExceptionIsThrownIfUpperLimitIsLessThanLower()
		{
			RangeStateColourSpecification.Parse("9-2 failures Yellow");
		}

        [Test, ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = "Metric 'failures': Cannot be more than 100. This is the number of errors stored\r\nParameter name: maximum\r\nActual value was 999.")]
        public void TestExceptionIsThrownIfUpperLimitIsMoreThanNumberStored()
        {
            RangeStateColourSpecification.Parse("99-999 failures Yellow");
        }

        [Test, ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = "Metric 'failures': Must be a whole number\r\nParameter name: maximum\r\nActual value was 999.99.")]
        public void TestExceptionIsThrownIfDecimalValueUsed()
        {
            RangeStateColourSpecification.Parse("99-999.99 failures Yellow");
        }

        [Test, ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = "Metric 'failures': Cannot be more than 100. This is the number of errors stored\r\nParameter name: minimum\r\nActual value was 150.")]
        public void TestExceptionIsThrownIfLowerLimitIsMoreThanNumberStored()
        {
            RangeStateColourSpecification.Parse("150-200 failures Yellow");
        }

		[Test, ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = "Must be zero or more\r\nParameter name: maximum\r\nActual value was -5.")]
		public void TestExceptionIsThrownIfBoundedRangeUpperLimitIsNegative()
		{
            RangeStateColourSpecification.Parse("3->-5 failures Yellow");
		}

		[Test, ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = "Must be zero or more\r\nParameter name: minimum\r\nActual value was -2.")]
		public void TestExceptionIsThrownIfBoundedRangeLowerLimitIsNegative()
		{
            RangeStateColourSpecification.Parse("-2->9 failures Yellow");
		}

		[Test, ExpectedException(typeof(FormatException), ExpectedMessage = "'MadeUp' is not a known colour. Some examples of colours are 'Red', 'Blue', 'Orange' and 'Green'")]
		public void TestExceptionIsThrownIfBoundedRangeColourNotKnown()
		{
            RangeStateColourSpecification.Parse("2-9 failures MadeUp");
		}

		[Test]
		public void TestCanParseSingleValue()
		{
            Assert.AreEqual("0 failures: Yellow", RangeStateColourSpecification.Parse("0 failures Yellow").Description);
            Assert.AreEqual("0 failures: Yellow", RangeStateColourSpecification.Parse(" 0  failures   Yellow ").Description);
            Assert.AreEqual("1 failure: Red", RangeStateColourSpecification.Parse("1 failures red").Description);
            Assert.AreEqual("80 failures: Red", RangeStateColourSpecification.Parse("80 failures red").Description);
            Assert.AreEqual("2 failures: Blue", RangeStateColourSpecification.Parse("2 failures blue").Description);
		}

		[Test, ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = "Must be zero or more\r\nParameter name: value\r\nActual value was -5.")]
		public void TestExceptionIsThrownIfSingleValueIsNegative()
		{
            RangeStateColourSpecification.Parse("-5 failures Yellow");
		}

		[Test, ExpectedException(typeof(FormatException), ExpectedMessage = "'MadeUp' is not a known colour. Some examples of colours are 'Red', 'Blue', 'Orange' and 'Green'")]
		public void TestExceptionIsThrownIfSingleValueColourNotKnown()
		{
            RangeStateColourSpecification.Parse("2 failures MadeUp");
		}

		[Test]
		public void TestCanParseLowerBoundedRange()
		{
            Assert.AreEqual("1 or more failures: Yellow", RangeStateColourSpecification.Parse("1+ failures Yellow").Description);
            Assert.AreEqual("1 or more failures: Yellow", RangeStateColourSpecification.Parse(" 1+ failures  Yellow ").Description);
            Assert.AreEqual("9 or more failures: Yellow", RangeStateColourSpecification.Parse("9+ failures yellow").Description);
            Assert.AreEqual("99 or more failures: Yellow", RangeStateColourSpecification.Parse("99+ failures yellow").Description);
            Assert.AreEqual("9 or more failures: Green", RangeStateColourSpecification.Parse("9-> failures  Green").Description);
            Assert.AreEqual("9 or more failures: Orange", RangeStateColourSpecification.Parse("9- failures  Orange").Description);
		}

		[Test, ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = "Must be zero or more\r\nParameter name: minimum\r\nActual value was -3.")]
		public void TestExceptionIsThrownIfLowerBoundedRangeValueIsNegative()
		{
            RangeStateColourSpecification.Parse("-3+ failures Yellow");
		}

		[Test, ExpectedException(typeof(FormatException), ExpectedMessage = "'MadeUp' is not a known colour. Some examples of colours are 'Red', 'Blue', 'Orange' and 'Green'")]
		public void TestExceptionIsThrownIfLowerBoundedRangeColourNotKnown()
		{
            RangeStateColourSpecification.Parse("2+ failures MadeUp");
		}

		[Test]
		public void TestCanParseUpperBoundedRange()
		{
            Assert.AreEqual("10 or fewer failures: Yellow", RangeStateColourSpecification.Parse("->10 failures Yellow").Description);
            Assert.AreEqual("10 or fewer failures: Yellow", RangeStateColourSpecification.Parse(" -> 10 failures  Yellow ").Description);
            Assert.AreEqual("100 or fewer failures: Yellow", RangeStateColourSpecification.Parse("->100 failures Yellow").Description);
            Assert.AreEqual("5 or fewer failures: Green", RangeStateColourSpecification.Parse("->5 failures green").Description);
		}

		[Test, ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = "Must be zero or more\r\nParameter name: maximum\r\nActual value was -4.")]
		public void TestExceptionIsThrownIfUpperBoundedRangeValueIsNegative()
		{
            RangeStateColourSpecification.Parse("->-4 failures Yellow");
		}

		[Test, ExpectedException(typeof(FormatException), ExpectedMessage = "'MadeUp' is not a known colour. Some examples of colours are 'Red', 'Blue', 'Orange' and 'Green'")]
		public void TestExceptionIsThrownIfUpperBoundedRangeColourNotKnown()
		{
            RangeStateColourSpecification.Parse("->2 failures MadeUp");
		}

	}
}
